import 'dart:convert';

import 'package:ty_smart_watch/bean/geo_bean.dart';
import 'package:ty_smart_watch/bean/more_weather_bean.dart';
import 'package:ty_smart_watch/bean/now_weather_bean.dart';
import 'package:ty_smart_watch/utils/Log.dart';
import 'package:ty_smart_watch/utils/util.dart';
import 'dart:math';
import 'dart:typed_data';
import 'package:intl/intl.dart';
import 'dart:developer' as developer;

/// 组合协议工具类
/// 仅关注数据部分，不关注功能码和数据长度
class ProtocolDataUtil {
  //region 单例模式
  static ProtocolDataUtil? _instance;

  factory ProtocolDataUtil() => _getInstance()!;

  static ProtocolDataUtil? get instance => _getInstance();

  static ProtocolDataUtil? _getInstance() {
    _instance ??= ProtocolDataUtil._internal();
    return _instance;
  }

  ProtocolDataUtil._internal() {
    _init();
  }

  _init() {}

  //endregion

  //region 基础信息
  /// 设备版本号0X0003
  List<int> getVersion() {
    return [];
  }

  //endregion

  //region 绑定类
  /// 绑定0X0101
  List<int> bind() => [];

  /// 支持的功能列表
  List<int> geFunctionList() => [];

  //endregion

//region 设置类

  /// 计步目标0X0201
  /// @param step 步数
  List<int> stepTarget(int step) {
    return Util.instance!.toByteArray(step);
  }

  ///  亮屏时间设置0X0202
  ///  @param second 亮屏时间 00：常亮， 01~3C：亮屏1~60秒
  // static List<int> screenBright(int second) {
  //   return Util.instance!.toByteArray(second);
  // }
  static List<int> screenBright(int second) {
    return [second];
  }

  /// 时间范围型功能通用方法
  /// @param switch 开关状态（0：关闭，1：打开）
  List<int> commonTimeRange(
    int switchValue,
    int startHour,
    int startMinute,
    int endHour,
    int endMinute,
    int duration,
  ) {
    return [
      switchValue & 0xFF,
      startHour & 0xFF,
      startMinute & 0xFF,
      endHour & 0xFF,
      endMinute & 0xFF,
      duration & 0xFF,
    ];
  }

  /// 久坐设置0X0203
  /// @param switch 开关状态（0：关闭，1：打开）
  List<int> longSit(
    int switchValue,
    int startHour,
    int startMinute,
    int endHour,
    int endMinute,
    int duration,
  ) {
    return [
      switchValue & 0xFF,
      startHour & 0xFF,
      startMinute & 0xFF,
      endHour & 0xFF,
      endMinute & 0xFF,
      duration & 0xFF,
    ];
  }

  /// 勿扰设置0X0204：
  /// @param switch 开关状态（0：关闭，1：打开，2：全天打开）
  List<int> doNotDisturb(
    int switchValue,
    int startHour,
    int startMinute,
    int endHour,
    int endMinute,
  ) {
    return [
      switchValue & 0xFF,
      startHour & 0xFF,
      startMinute & 0xFF,
      endHour & 0xFF,
      endMinute & 0xFF,
    ];
  }

  /// 震动设置0X0205
  /// @param level "震动强度：01：弱  02：中  03强"
  /// @param times 震动次数：0~10次
  static List<int> shake(int level, int times) {
    return [
      level & 0xFF,
      times & 0xFF,
    ];
  }

  /// 抬手亮屏设置0X0206
  /// @param switch 开关状态（0：关闭，1：打开）
  List<int> handBrighten(
    int switchValue,
    int startHour,
    int startMinute,
    int endHour,
    int endMinute,
  ) {
    return [
      switchValue & 0xFF,
      startHour & 0xFF,
      startMinute & 0xFF,
      endHour & 0xFF,
      endMinute & 0xFF,
    ];
  }

  ///  12/24小时制设置0X0207
  ///  @param type 0：24小时制，1：12小时制
  List<int> hourType(int type) {
    return [
      type & 0xFF,
    ];
  }

  ///  语言设置0X0207
  ///  @param language 语言种类
  ///   0x00	简体中文
  ///   0x01	繁体中文
  ///   0x02	英语
  ///   0x03	西班牙语
  ///   0x04	俄语
  ///   0x05	日语
  ///   0x06	韩语
  ///   0x07	法语
  ///   0x08	葡萄牙语
  static List<int> language(int language) {
    return [
      language & 0xFF,
    ];
  }

  /// 闹钟设置0X0209
  /// @param type 闹钟类型："新增：0X00 修改：0X01 删除：0X02"
  /// @param id 闹钟ID（0~255）
  /// @param switch 开关状态（0：关闭，1：打开）
  /// @param repeat 是否重复
  /// @param dayOfWeek "bit0：（0：单次，1：重复） bit1~7：对应周一到周日"
  static List<int> alarm(
    int type,
    int id,
    int switchValue,
    bool repeat,
    int hour,
    int minute,
    List<int> dayOfWeek,
  ) {
    Log.d("闹钟重复星期:$dayOfWeek");
    List<int> result = List.filled(6, 0);
    int data3 = 0x00;
    for (int i = 0; i < dayOfWeek.length; i++) {
      if (dayOfWeek[i] != 0) {
        data3 += pow(2, i).toInt();
      }
    }
    data3 *= 2;
    if (repeat) data3++;
    result[0] = type & 0xFF;
    result[1] = id & 0xFF;
    result[2] = switchValue & 0xFF;
    result[3] = data3 & 0xFF;
    result[4] = hour & 0xFF;
    result[5] = minute & 0xFF;
    return result;
  }

  /// 消息通知开关设置0X020A
  /// @param switch 总开关（0：关闭，1：打开）
  /// @param appList 消息列表
  List<int> notificationSwitch(int switchValue, List<int> appList) {
    List<int> result = [switchValue & 0xFF];
    result.add(fillByte(appList.sublist(0, 8)));
    result.add(fillByte(appList.sublist(8, 16)));
    result.add(fillByte(appList.sublist(16, 24)));
    result.add(fillByte(appList.sublist(24, 32)));
    return result;
  }

  /// 定时心率设置0X020B
  /// @param switch 开关状态（0：关闭，1：打开）
  /// @param duration 测量间隔时间：0~255分
  List<int> timeHeart(
    int switchValue,
    int startHour,
    int startMinute,
    int endHour,
    int endMinute,
    int duration,
  ) {
    return [
      switchValue,
      startHour,
      startMinute,
      endHour,
      endMinute,
      duration,
    ];
  }

  /// 喝水提醒设置0X020C
  /// @param switch 开关状态（0：关闭，1：打开）
  /// @param duration 喝水间隔时间：0~255分
  List<int> drinkRemind(
    int switchValue,
    int startHour,
    int startMinute,
    int endHour,
    int endMinute,
    int duration,
  ) {
    return [
      switchValue,
      startHour,
      startMinute,
      endHour,
      endMinute,
      duration,
    ];
  }

  /// 吃药提醒设置0X020D
  /// @param switch 开关状态（0：关闭，1：打开）
  List<int> medicineRemind(
    int switchValue,
    int hour,
    int minute,
  ) {
    return [
      switchValue,
      hour,
      minute,
    ];
  }

  /// 生理期设置0X020E
  /// @param switch 开关状态（0：关闭，1：打开）
  /// @param year 开始时间（2023年，写23）
  /// @param month 开始时间（月）
  /// @param day 开始时间（月）
  /// @param duration 持续时间（天）
  List<int> period(
    int switchValue,
    int year,
    int month,
    int day,
    int duration,
  ) {
    return [
      switchValue,
      year,
      month,
      day,
      duration,
    ];
  }

  /// 定时体温设置0X020F
  /// @param switch 开关状态（0：关闭，1：打开）
  /// @param duration 体温测量间隔时间：0~255分
  List<int> bodyTemperature(
    int switchValue,
    int startHour,
    int startMinute,
    int endHour,
    int endMinute,
    int duration,
  ) {
    return [
      switchValue,
      startHour,
      startMinute,
      endHour,
      endMinute,
      duration,
    ];
  }

  ///  防丢设置0X0210
  ///  @param switch 开关状态（0：关闭，1：打开）
  List<int> antiLose(int switchValue) {
    return [
      switchValue,
    ];
  }

  ///  公英制设置0X0211
  ///  @param type 0：公制，1：英制
  List<int> inchType(int type) {
    return [
      type,
    ];
  }

  ///  天气温度单位0X0212
  ///  @param type 0：摄氏度，1：华氏度
  List<int> temperatureType(int type) {
    return [
      type,
    ];
  }

  /// SOS联系人设置0X0213
  /// @param type 类型 "新增：0X00 修改：0X01 删除：0X02"
  /// @param number 号码
  /// @param name 名称
  static List<int> sos(int type, int id, String number, String name) {
    // 电话号是20位，如果不足20位用空格代替
    var num = number;
    while (num.length < 20) {
      num += " ";
    }

    List<int> bType = [type];
    List<int> bId = [id];
    List<int> bNum = utf8.encode(num);
    List<int> bName = utf8.encode(name);
    List<int> result = [...bType, ...bId, ...bNum, ...bName];
    return result;
  }

  /// 手表控制通话 0x0215  只有设备能发送

  ///  找手机功能 0X0216：（手机点击响铃关闭弹窗，下发关闭响铃）
  ///  @param type "00：打开响铃  01：关闭响铃"
  List<int> findPhone(int type) {
    return [type];
  }

  ///  找手表 0x0217
  List<int> findWatch() {
    return [];
  }

  ///  拍照控制 0X0218
  ///  @param type "01:打开相机  02:退出相机"
  List<int> photoControl(int type) {
    return [type];
  }

  /// 用户信息设置 0x0219
  /// @param sex 性别（0：男，1：女）
  /// @param age 年龄
  /// @param height 身高（cm）
  /// @param weight 体重（kg）
  List<int> userInfo(int sex, int age, int height, int weight) {
    return [0x00, sex, age, height, weight];
  }

  /// 消息推送 0X0401
  /// @param timestamp 时间戳 1~4
  /// @param title 消息标题 5~44
  /// @param msg 消息内容 最大250字节 45~n
  List<int> notifyMsg(int id, int timestamp, String title, String msg) {
    // App ID
    List<int> bId = [id];
    // 时间戳
    List<int> timeStamp = timestampToByteArray(/*System.currentTimeMillis()*/ timestamp);
    // 消息标题
    List<int> bTitle = utf8.encode(title.padRight(40));
    // 消息内容
    List<int> bMsg = utf8.encode(msg.substring(0, min(250, msg.length)));

    return [...bId, ...timeStamp, ...bTitle, ...bMsg];
  }

  /// 天气推送 0X0403
  ///
  List<int> currentWeather(
    GeoBean geoBean,
    NowWeatherBean weatherBean,
    MoreWeatherBean futureWeatherBean,
    int timestamp,
  ) {
    Log.d("geoBean: $geoBean");
    Log.d("weatherBean: $weatherBean");
    Log.d("futureWeatherBean: $futureWeatherBean");
    Log.d("timestamp: $timestamp");

    // 地址 长春,朝阳
    final adm2 = geoBean.location?[0].adm2 ?? '';
    final name = geoBean.location?[0].name ?? '';
    final geo = '$adm2,$name';
    final bGeo = Uint8List.fromList(utf8.encode(geo));
    final bGeoLength = Uint8List.fromList([bGeo.length]);

    // 时间戳
    final bTimeStamp = timestampToByteArray(timestamp);

    // 当前温度
    final bCurrent = int.parse(weatherBean.now?.temp ?? "0");

    // 最高温
    final tempMax = int.parse(futureWeatherBean.daily?[0].tempMax ?? "0");
    int bTempMax = tempMax.abs();
    bTempMax = tempMax < 0 ? bTempMax | 0x80 : bTempMax;

    // 最低温
    final tempMin = int.parse(futureWeatherBean.daily?[0].tempMin ?? "0");
    int bTempMin = tempMin.abs();
    bTempMin = tempMin < 0 ? bTempMin | 0x80 : bTempMin;

    // 天气类型
    final bType = changeWeatherType(int.parse(weatherBean.now?.icon ?? "-1"));

    // 湿度
    final bHumidity = int.parse(weatherBean.now?.humidity ?? "0");

    // 降雨量
    final precip = weatherBean.now?.precip ?? '0';
    final split = precip.split('.');
    final iPrecip = int.parse(split[0]);
    final bPrecip = iPrecip;

    // 风速
    final bWindSpeed = int.parse(weatherBean.now?.windSpeed ?? "0");

    // 紫外线等级
    final bUv = int.parse(futureWeatherBean.daily?[0].uvIndex ?? "0");

    return Uint8List.fromList(bGeoLength +
        bGeo +
        bTimeStamp +
        [bCurrent] +
        [bTempMax] +
        [bTempMin] +
        [bType] +
        [bHumidity] +
        [bPrecip] +
        [bWindSpeed] +
        [bUv]);
  }

  /// 未来天气推送 0X0404
  List<int> futureWeather(GeoBean geoBean, MoreWeatherBean futureWeatherBean) {
    List<int> result = Uint8List(0);

    // 地址 长春,朝阳
    String adm2 = geoBean.location?[0].adm2 ?? "";
    String name = geoBean.location?[0].name ?? "";
    String geo = "$adm2,$name";
    Uint8List bGeo = utf8.encode(geo);
    Uint8List bGeoLength = Uint8List.fromList([bGeo.length]);

    result = [...result, ...bGeoLength, ...bGeo];

    // 未来天气for in
    int dataSize = futureWeatherBean.daily?.length ?? 0;
    for (int i = 0; i < dataSize; i++) {
      // 时间戳
      String? rawTimeStamp = futureWeatherBean.daily?[i].fxDate ?? "1970-01-01";
      int dateToTimeStamp = DateTime.parse(rawTimeStamp).millisecondsSinceEpoch ~/ 1000;
      List<int> bTimeStamp = dateTimestampToByteArray(dateToTimeStamp);

      // 最高温
      int tempMax = int.parse(futureWeatherBean.daily?[i].tempMax ?? "0");
      int bTempMax = tempMax.abs().toUnsigned(8);
      if (tempMax < 0) {
        bTempMax |= 0x80;
      }
      // 最低温
      int tempMin = int.parse(futureWeatherBean.daily?[i].tempMin ?? "0");
      int bTempMin = tempMin.abs().toUnsigned(8);
      if (tempMin < 0) {
        bTempMin |= 0x80;
      }
      // 天气类型
      int bType = changeWeatherType(int.parse(futureWeatherBean.daily?[i].iconDay ?? "-1"));
      // 湿度
      int bHumidity = int.parse(futureWeatherBean.daily?[i].humidity ?? "0");
      // 降雨量
      String precip = futureWeatherBean.daily?[i].precip ?? "0";
      List<String> split = precip.split(".");
      int iPrecip = int.parse(split[0]);
      int bPrecip = iPrecip.toUnsigned(8);
      // 风速
      int bWindSpeed = int.parse(futureWeatherBean.daily?[i].windSpeedDay ?? "0");
      // 紫外线等级
      int bUv = int.parse(futureWeatherBean.daily?[0].uvIndex ?? "0");

      result.addAll(bTimeStamp);
      result.add(bTempMax);
      result.add(bTempMin);
      result.add(bType);
      result.add(bHumidity);
      result.add(bPrecip);
      result.add(bWindSpeed);
      result.add(bUv);
    }
    return result;
  }

  /// 来电推送 0X0406
  /// @param type 电话类型
  /// @param timestamp 时间戳 1~4
  /// @param name 来电姓名
  /// @param phone 来电号码
  List<int> notifyMsgPhone(int type, int timestamp, String name, String phone) {
    // 电话类型
    var bId = Uint8List.fromList([type.toUnsigned(8)]);
    // 时间戳
    var timeStamp = timestampToByteArray(timestamp);
    // 来电姓名
    var bName = utf8.encode(name);
    // 来电姓名长度
    var bNameLength = Uint8List.fromList([bName.length]);
    // 电话号码
    var bPhone = utf8.encode(phone);
    // 电话号码长度
    var bPhoneLength = Uint8List.fromList([bPhone.length]);

    return Uint8List.fromList(bId + timeStamp + bNameLength + bName + bPhoneLength + bPhone);
  }

  /// 时间更新 0x405
  List<int> updateTime(int timestamp) {
    // 结果
    var result = Uint8List(6);
    // 时间戳
    var timeStamp = timestampToByteArray(timestamp);
    for (var i = 0; i < 4; i++) {
      result[i] = timeStamp[i];
    }
    // 星期转换
    var dayOfWeek = DateTime.now().weekday;
    if (dayOfWeek == DateTime.sunday) {
      dayOfWeek = 7;
    } else {
      dayOfWeek -= 1;
    }
    // 时区
    var rawOffset = DateTime.now().timeZoneOffset.inMilliseconds;
    var offset = rawOffset ~/ (15 * 60 * 1000);
    // 时区转换
    var zoneResult = offset.abs().toUnsigned(8);
    if (offset > 0) {
      zoneResult &= 0x7F;
    } else {
      zoneResult |= 0x80;
    }

    result[4] = dayOfWeek.toUnsigned(8);
    result[5] = zoneResult;

    // CommonViewModel().timeZoneRawOffset = rawOffset;

    print('更新时间: ${Util.instance!.toHexString(result)}');
    return result;
  }

  ///
  int fillByte(List<int> data) {
    int temp = 0;
    for (int i = 0; i < data.length; i++) {
      int d = data[i];
      if (d != 0) {
        temp += pow(2, i).toInt();
      }
    }
    print('fillByte: $temp');
    return temp & 0xFF; // Ensure the result fits within a byte (0-255)
  }

  int dateToTimeStamp(String date) {
    DateFormat dateFormat = DateFormat("yyyy-MM-dd");
    try {
      DateTime d = dateFormat.parse(date);
      return (d.millisecondsSinceEpoch ~/ 1000);
    } catch (e) {
      developer.log("dateToTimeStamp exception: ${e.toString()}");
      return 0;
    }
  }

  List<int> timestampToByteArray(int timestamp) {
    int timestampInSeconds = timestamp ~/ 1000; // 将时间戳从毫秒转换为秒
    ByteData byteData = ByteData(4);
    byteData.setInt32(0, timestampInSeconds, Endian.big);
    return byteData.buffer.asUint8List();
  }

  List<int> dateTimestampToByteArray(int timestamp) {
    ByteData byteData = ByteData(4);
    byteData.setInt32(0, timestamp, Endian.big);
    return byteData.buffer.asUint8List();
  }

  int changeWeatherType(int type) {
    if (type >= 100 && type < 110) {
      return type - 100;
    } else if (type >= 150 && type < 160) {
      return type - 150;
    } else if (type >= 300 && type < 320) {
      return type - 295;
    } else if (type >= 350 && type < 352) {
      return type - 345;
    } else if (type == 399) {
      return 24;
    } else if (type >= 400 && type <= 410) {
      return type - 375;
    } else if (type >= 456 && type < 458) {
      return type - 425;
    } else if (type == 499) {
      return 36;
    } else if (type >= 500 && type <= 504) {
      return type - 463;
    } else if (type >= 507 && type <= 515) {
      return type - 465;
    } else if (type == 900) {
      return 51;
    } else if (type == 901) {
      return 52;
    } else {
      return 255;
    }
  }
}
